package ch.epfl.lara.pm.analyze.set;

import ch.epfl.lara.pm.util.MyImplicitConversions

object IPatternsAsSets extends MyImplicitConversions {

  type Set = List[String]
  type PatternSet = (String,String)
  
  /**
   * Translate the list of patterns into a list of set with the particularity that each
   * set has the same dimension (same number of element in the list). 
   * It can be seen as an homogenized transformation of patterns into set in such a way
   * that the comparison among them is possible.
   */
  def apply(map: PatternMap, prefined: List[IPatternRefinedDef]): List[Set] = {
    val list_of_patternset = toPatternSet(map,prefined)
    val metasets = map.getCompleteMetaSet
    (for(patternset <- list_of_patternset) yield {
      for(meta <- metasets) yield { 
        patternset.find(pair => pair._1 == meta) match {
          case None => 
            map.getConcreteSet(meta) match {
              case None => error("missing metaset "+meta+" in pattern map!")
              case Some(List(tpe)) => tpe
              case Some(many) => many.head
            }
            
          case Some((_,tpe)) => tpe
        }
      }
    })
    
  }
  
  /**
   * Translate the list of patterns into a list of set with.
   * Be aware that each set can have a different number of elements. Thus, comparison
   * among sets is not possible because they may belong to different universes.  
   */
  private def toPatternSet(map: PatternMap, patterns: List[IPatternRefinedDef]): List[List[PatternSet]] = {
    def makePair(path: String,tpe: String) =  map.getMetaset(path) match {
      case None => Nil
      case Some(metaset) => List((metaset,tpe))
    }
    def makeSet(pattern: IPatternRefinedDef): List[PatternSet] = pattern match {
      case IVarPattern(tpe,path) => makePair(path,tpe)
      case IClassPattern(objname,ifields,path) => makePair(path,objname) ::: ifields.flatMap(makeSet _)
      case IWildcardPattern => Nil
      case IPatternRefined(_,_) => error("Refined Pattern should not exist anymore")
    }
    patterns.map(makeSet _) 
  }
  
}
